package cc.shacocloud.mirage.kotlin.restful

import cc.shacocloud.mirage.kotlin.*
import cc.shacocloud.mirage.kotlin.Slf4j.Companion.log
import cc.shacocloud.mirage.restful.*
import cc.shacocloud.mirage.restful.bind.WebDataBinderFactory
import cc.shacocloud.mirage.utils.MethodParameter
import io.vertx.core.Future
import io.vertx.kotlin.coroutines.await
import java.lang.reflect.Method
import java.util.*

/**
 * 基于 kotlin 实现的处理器方法映射
 * @author 思追(shaco)
 *
 */
@Slf4j
class KotlinVertxInvocableHandlerMethod : VertxInvocableHandlerMethod {

    constructor(handler: Any, method: Method) : super(handler, method)
    constructor(handlerMethod: HandlerMethod) : super(handlerMethod)

    init {
        parameters = initMethodParameters()
    }

    override fun buildMethodParameter(index: Int): MethodParameter {
        return KotlinHandlerMethodParameter(this, index)
    }

    override fun createWithResolvedBean(): HandlerMethod {
        return KotlinVertxInvocableHandlerMethod(super.createWithResolvedBean())
    }

    override fun createInvocableHandlerMethodAndCopyProperty(handlerMethod: HandlerMethod): InvocableHandlerMethod {
        if (handlerMethod === this) return this

        // 如果是协程方法则使用 KotlinVertxInvocableHandlerMethod 处理器
        if (isSuspendingFunction(handlerMethod)) {
            val invocableHandlerMethod = KotlinVertxInvocableHandlerMethod(handlerMethod)
            invocableHandlerMethod.setParameterNameDiscoverer(parameterNameDiscoverer)

            // 拓展协程方法参数解析器
            val methodArgumentResolver = resolvers ?: HandleMethodArgumentResolverComposite()
            invocableHandlerMethod.setHandlerMethodArgumentResolvers(methodArgumentResolver)

            return invocableHandlerMethod
        }

        return super.createInvocableHandlerMethodAndCopyProperty(handlerMethod)
    }

    override fun invokeForRequest(
        request: HttpRequest,
        binderFactory: WebDataBinderFactory,
        vararg providedArgs: Any?
    ): Future<*> {
        if (log.isDebugEnabled) {
            log.debug("方法 '${description}' 进入参数解析过程...")
        }

        return mirageLaunch {

            val mirageContinuation = MirageContinuationContext(it)

            // 获取方法参数值
            val args = getMethodArgumentValues(request, binderFactory, *providedArgs, mirageContinuation).await()

            if (log.isDebugEnabled) {
                log.debug("\n执行目标方法：$method \n参数：${Arrays.toString(args)}")
            }

            return@mirageLaunch doMethodInvoke(it, bean, method, *args);
        }
    }

    /**
     * kotlin 的方法参数
     */
    class KotlinHandlerMethodParameter(handlerMethod: HandlerMethod, i: Int) :
        HandlerMethodParameter(handlerMethod, i) {

        override fun getParameterName(): String? {
            if (isCoroutinesMethodParameter(this)) {
                return "\$completion"
            }
            return super.getParameterName()
        }

    }


}